#include "EffectManager.h"
#include "EffectBase.h"
#include "StormLightning.h"

EffectManager * EffectManager::selfSingleton = NULL;

EffectManager::~EffectManager()
{

}

EffectManager::EffectManager()
{
	mFullScreenMaskAlpha = 0.5f;
	m_pFullScreenManualObject = NULL;
	Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create("FullScreenMaskMat", "General");
	material->getTechnique(0)->getPass(0)->createTextureUnitState("white.png");
	material->getTechnique(0)->getPass(0)->setAmbient(1.0f,1.0f,1.0f);
	material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false);
	material->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
	material->getTechnique(0)->getPass(0)->setLightingEnabled(false);
	material->getTechnique(0)->getPass(0)->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);

}

EffectManager* EffectManager::getInstance()
{
	if(EffectManager::selfSingleton == NULL)
	{
		EffectManager::selfSingleton = new EffectManager();
	}
	return EffectManager::selfSingleton;
}

void EffectManager::registerEffectInstance(UTFString name, EffectBase* instance)
{
	std::pair<UTFString, EffectBase*> _p;
	_p.first = name;
	_p.second = instance;
	mEffectMap.insert(_p);
}

void EffectManager::registerVanishPass(Ogre::Pass *pass, Ogre::Real timeLeft, 
									   VanishFunctionType type,
									   Ogre::Real *param)
{
	VanishElement *pve = new VanishElement();
	pve->pass = pass;
	pve->timeLeft = timeLeft;
	pve->timePassed = 0;
	pve->vft = type;
	for (int i = 0; i<10; i++)
	{
		pve->vft_para[i] = *(param+i);
	}
	pve->needErase = false;

	mVanishingPass.push_back(pve);

}

void EffectManager::_vanishProcess(VanishElement * pve, Ogre::Real timeSinceLast)
{
	Ogre::Real alphaVanish = 0;

	switch(pve->vft)
	{
	case VFT_LINEAR:
		{
			Ogre::Real a = pve->vft_para[0];
			Ogre::Real b = pve->vft_para[1];
			alphaVanish = EffectBase::vanishFunction_Linear(pve->timePassed,a,b);
			pve->timePassed += timeSinceLast;
			pve->timeLeft -= timeSinceLast;
		}
		break;

	case VFT_PARA:
		{
			Ogre::Real a = pve->vft_para[0];
			Ogre::Real b = pve->vft_para[1];
			Ogre::Real c = pve->vft_para[2];
			alphaVanish = EffectBase::vanishFunction_Parabola(pve->timePassed, a ,b ,c);
			pve->timePassed += timeSinceLast;
			pve->timeLeft -= timeSinceLast;
		}
		break;
	case VFT_TRIANGLUAR:
		{
			Ogre::Real a = pve->vft_para[0];
			Ogre::Real b = pve->vft_para[1];
			alphaVanish = EffectBase::vanishFunction_Triangular(pve->timePassed, a ,b);
			pve->timePassed += timeSinceLast;
			pve->timeLeft -= timeSinceLast;
		}
		break;
	default:
		break;
	}

	if (pve->timeLeft > 0)
	{
		Ogre::Pass * pPass = pve->pass;
		pPass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
		pPass->setTransparentSortingEnabled(true);
		pPass->getTextureUnitState(0)->setAlphaOperation(
			Ogre::LBX_MODULATE_X2, 
			Ogre::LBS_MANUAL, 
			Ogre::LBS_TEXTURE,
			alphaVanish);
	}
	else
	{
		Ogre::Pass * pPass = pve->pass;
		pPass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
		pPass->setTransparentSortingEnabled(true);
		pPass->getTextureUnitState(0)->setAlphaOperation(
			Ogre::LBX_MODULATE, 
			Ogre::LBS_TEXTURE,
			Ogre::LBS_CURRENT); 
		pve->needErase = true;

		//special case for full screen mask
		if(pPass == mFullScreenMaskPass)
		{
			m_pSceneMgr->destroyManualObject(m_pFullScreenManualObject);
			m_pFullScreenManualObject = NULL;
		}
	}
	
}

void EffectManager::update(Ogre::Real timeSinceLast)
{
	for (EffectMap::iterator it = mEffectMap.begin(); it != mEffectMap.end(); ++it)
	{
		it->second->update(timeSinceLast);
	}

	for (unsigned int i = 0; i<mVanishingPass.size(); i++)
	{
		_vanishProcess(mVanishingPass[i], timeSinceLast);
	}
	//for erase
	int i = -1;
	for (VanishElementVector::iterator it = mVanishingPass.begin();
		it!=mVanishingPass.end(); it++)
	{
		i++;
		if (mVanishingPass[i]->needErase)
		{
			delete mVanishingPass[i];
			it = mVanishingPass.erase(it);
			i = -1;
			it = mVanishingPass.begin();
			if(mVanishingPass.size()==0)
				break;
			/*mVanishingPass.begin();
			i = -1;*/
		}
	}

}

void EffectManager::eventClick(int _xx, int _yy)
{
	for (EffectMap::iterator it = mEffectMap.begin(); it != mEffectMap.end(); ++it)
	{
		it->second->eventClick(_xx, _yy);
	}
}
void EffectManager::eventMouseMove(int _x, int _y, int _xRel, int _yRel, bool isButtonDown)
{
	for (EffectMap::iterator it = mEffectMap.begin(); it != mEffectMap.end(); ++it)
	{
		it->second->eventMouseMove(_x,_y,_xRel,_yRel,isButtonDown);
	}
}
void EffectManager::eventMouseRelease(int _xx, int _yy)
{
	for (EffectMap::iterator it = mEffectMap.begin(); it != mEffectMap.end(); ++it)
	{
		it->second->eventMouseRelease(_xx, _yy);
	}
}
void EffectManager::stateMouseDown(int _x, int _y, int _xRel, int _yRel, bool isButtonDown)
{
	for (EffectMap::iterator it = mEffectMap.begin(); it != mEffectMap.end(); ++it)
	{
		it->second->stateMouseDown(_x,_y,_xRel,_yRel,isButtonDown);
	}
}

void EffectManager::setParNeeded(SceneManager * _mgr, Camera *_c)
{
	m_pSceneMgr = _mgr;
	m_pCamera = _c;
}

void EffectManager::createEffect(UTFString name, EffectType type)
{
	switch (type)
	{
	case EFT_STORMLIGHTNING:
		StormLightning *_effect_new = new StormLightning();
		_effect_new->init(m_pSceneMgr,m_pCamera);
		_effect_new->load();
		_effect_new->setEnabled(false);
		registerEffectInstance(name,_effect_new);
		break;
	}
}

EffectBase * EffectManager::getEffect(Ogre::UTFString name)
{
	EffectMap::iterator it = mEffectMap.find(name);
	if(it != mEffectMap.end())
		return it->second;
	else
		return NULL;
}

Ogre::Pass* EffectManager::_createFullScreenMask(Vector3 rgbColor)
{
	
	//material->getTechnique(0)->getPass(0)->setTransparentSortingEnabled(true);
	/*material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setAlphaOperation(
		Ogre::LBX_MODULATE, 
		Ogre::LBS_MANUAL, 
		Ogre::LBS_TEXTURE,
		mFullScreenMaskAlpha); */
	Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName("FullScreenMaskMat");
	m_pFullScreenManualObject = m_pSceneMgr->createManualObject();

	m_pFullScreenManualObject->setUseIdentityProjection(true);
	m_pFullScreenManualObject->setUseIdentityView(true);
	m_pFullScreenManualObject->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY);
	m_pFullScreenManualObject->begin("FullScreenMaskMat", Ogre::RenderOperation::OT_TRIANGLE_LIST );

	m_pFullScreenManualObject->position( -1.0f, -1.0f,-1.0f   );
	m_pFullScreenManualObject->textureCoord(0,1);
	m_pFullScreenManualObject->colour(rgbColor.x,rgbColor.y,rgbColor.z);
	m_pFullScreenManualObject->position( 1.0f, -1.0f,-1.0f   );
	m_pFullScreenManualObject->textureCoord(1,1);
	m_pFullScreenManualObject->colour(rgbColor.x,rgbColor.y,rgbColor.z);
	m_pFullScreenManualObject->position( 1.0f, 1.0f,-1.0f   );
	m_pFullScreenManualObject->textureCoord(1,0);
	m_pFullScreenManualObject->colour(rgbColor.x,rgbColor.y,rgbColor.z);
	m_pFullScreenManualObject->position( 1.0f, 1.0f,-1.0f   );
	m_pFullScreenManualObject->textureCoord(1,0);
	m_pFullScreenManualObject->colour(rgbColor.x,rgbColor.y,rgbColor.z);
	m_pFullScreenManualObject->position( -1.0f, 1.0f,-1.0f   );
	m_pFullScreenManualObject->textureCoord(0,0);
	m_pFullScreenManualObject->colour(rgbColor.x,rgbColor.y,rgbColor.z);
	m_pFullScreenManualObject->position( -1.0f, -1.0f,-1.0f   );
	m_pFullScreenManualObject->textureCoord(0,1);
	m_pFullScreenManualObject->colour(rgbColor.x,rgbColor.y,rgbColor.z);

	m_pFullScreenManualObject->end();
	m_pFullScreenManualObject->setVisible(true);
	m_pFullScreenManualObject->setBoundingBox(Ogre::AxisAlignedBox(-100000.0*Ogre::Vector3::UNIT_SCALE, 100000.0*Ogre::Vector3::UNIT_SCALE));
	m_pSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(m_pFullScreenManualObject);

	return material->getTechnique(0)->getPass(0);


}

void EffectManager::triggerFullScreenMaskVanish(Vector3 rgbColor,Ogre::Real timeLeft, 
												VanishFunctionType type,
												Ogre::Real *param)
{
	
	if (m_pFullScreenManualObject == NULL)
	{
		//m_pSceneMgr->destroyManualObject(m_pFullScreenManualObject);
		mFullScreenMaskPass = _createFullScreenMask(rgbColor);
		registerVanishPass(mFullScreenMaskPass,timeLeft,type,param);	
	}
	
}
